#pragma once

#include "FiringEvent.h"
#include "Triplet.h"

using namespace System::Collections;

namespace SpikingNeuronLib
{
	public ref class Pattern : public IStructuralEquatable
	{
	protected:
		int _uniqueID;										// a unique ID for this Pattern (normally a hash of the Pattern)

		List<FiringEvent>^ _firings;

		Triplet^ GetInitialTriplet();
		HashSet<int>^ GetPatternNeurons();
		static List<FiringEvent>^ ConvertFromStringImpl(String^ firingsString);
		static String^ ConvertToStringImpl(List<FiringEvent>^ firings);

	public:
		Pattern(String^ firingEvents);
		Pattern(System::Collections::Generic::IEnumerable<FiringEvent>^ firingEvents);
		Pattern(System::Collections::Generic::IEnumerable<Tuple<int, int>^>^ firingEvents);
		Pattern(array<FiringEvent>^ firingArray);
		Pattern(List<FiringEvent>^ firingsList);
		Pattern(List<FiringEvent>^ firingsList, int uniqueID);

		// truncated copy of the parent stimulus
		// the UniqueID is inherited from the parent Stimulus allowing parent and child to be linked
		Pattern(Pattern^ parentPattern, int maxFiringEvents);

		// IStructuralEquatable methods
		virtual bool Equals(Object^ other, System::Collections::IEqualityComparer^ comparer) sealed;
		virtual int GetHashCode(System::Collections::IEqualityComparer^ comparer) sealed;

		void SetUniqueID(int uniqueID) { _uniqueID = uniqueID; }

		property int UniqueID
		{
		public:
			int get()
			{
				return _uniqueID;
			}
		}

		property bool IsEmpty
		{
		public:
			virtual bool get()
			{
				// the pattern has no firing events
				return (_firings->Count == 0);
			}
		}

		property List<FiringEvent>^ EventList
		{
		public:
			List<FiringEvent>^ get()
			{
				return _firings;
			}
		}

		property int Count
		{
		public:
			int get()
			{
				return _firings->Count;
			}
		}

		property Triplet^ InitialTriplet
		{
		public:
			Triplet^ get()
			{
				return this->GetInitialTriplet();
			}
		}

		property HashSet<int>^ PatternNeurons
		{
		public:
			HashSet<int>^ get()
			{
				return this->GetPatternNeurons();
			}
		}

		virtual String^ ToString() override;

		System::Collections::Generic::IEnumerable<Tuple<int, int>^>^ GetEventTuples();
		System::Collections::Generic::IEnumerable<FiringEvent>^ GetFiringEvents();

		static String^ ConvertToString(Pattern^ pattern);
		static Pattern^ ConvertFromString(String^ firingsString);
	};
}
